#pragma once
#include "socket.hpp"
#include <sys/select.h>
using namespace socket_module;
class select_server
{
public:
    // 位图表示文件描述符数量 所以*8
    const static int max_size = sizeof(fd_set) * 8;
    int default_fd = -1;

public:
    select_server(int port)
        : _listen_socket(std::make_unique<TcpSocket>()),
          _is_running(false)
    {
        _listen_socket->BulidTcpSocket(port);
        for (int i = 0; i < max_size; i++)
        {
            _fds[i] = default_fd;
        }
        _fds[0] = _listen_socket->Fd();
    }

    void start()
    {
        _is_running = true;
        while (_is_running)
        {
            fd_set rfds;
            FD_ZERO(&rfds);
            int maxfd = default_fd;
            for (int i = 0; i < max_size; i++)
            {
                if (_fds[i] == default_fd)
                    continue;
                FD_SET(_fds[i], &rfds);
                if (maxfd < _fds[i])
                    maxfd = _fds[i];
            }
            Print_fd();
            struct timeval timeout = {1, 0};
            int n = select(maxfd + 1, &rfds, nullptr, nullptr, &timeout);
            switch (n)
            {
            case -1:
                LOG(log_level::ERROR) << "select error";
                break;
            case 0:
                LOG(log_level::INFO) << "Time out";
                break;
            default:
                LOG(log_level::DEBUG) << "something ready";
                Dispatcher(rfds);
                break;
            }
        }
    }
    void Dispatcher(fd_set& rfds)
    {
        for(int i=0;i<max_size;i++)
        {
            if(_fds[i]==default_fd) continue;
            if(FD_ISSET(_fds[i],&rfds))
            {
                //新链接
                if(_fds[i]==_listen_socket->Fd())
                {
                    Accepter();
                }
                else
                {
                    //传入i是为了方便关闭文件描述符
                    Recver(_fds[i],i);
                }
            }
        }
    }
    void Accepter()
    {
        InetAddr client;
        std::shared_ptr<Socket> tmp_sock=_listen_socket->Accept(client);
        int sockfd=tmp_sock->Fd();
        LOG(log_level::INFO)<<"Get a new Link.Port is"<<sockfd<<"Client is"<<client.addr_name();
        for(int i=0;i<max_size;i++)
        {
            if(_fds[i]==default_fd)
            {
                _fds[i]=sockfd;
                break;
            }
        }
    }

    void Recver(int fd,int pos)
    {
        //文件描述符放满了的情况没有处理
        char buffer[1024];
        ssize_t n=recv(fd,buffer,sizeof(buffer)-1,0);
        switch (n)
            {
            case -1:
                LOG(log_level::ERROR) << "recv error";
                _fds[pos]=default_fd;
                close(fd);
                break;
            case 0:
                LOG(log_level::INFO) << "Client quit";
                _fds[pos]=default_fd;
                close(fd);
                break;
            default:
                std::cout << "Client say#"<<buffer<<std::endl;
                break;
            }
    }
    void Print_fd()
    {
        for (int i = 0; i < max_size; i++)
        {
            if(_fds[i]==default_fd)
                continue;
            std::cout << _fds[i] << " ";
        }
        std::cout << std::endl;
    }
    void Stop()
    {
        _is_running=false;
    }
private:
    std::unique_ptr<Socket> _listen_socket;
    bool _is_running;
    int _fds[max_size];
};